#
# Gimme Go -- a GNOME go client
# Copyright (C) 2006  Ken Harris <kengruven@gmail.com>
# 
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
# 
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
# 
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
#

import gtk
import gtk.gdk

## TODO: respond to signals, like node_added

from count import count # FUTURE: generic 'util' package?

class GameTreeView(gtk.TreeView):
    """
    A tree-view of a game

    input: a Game tree object

    it looks like:

     * Start (or Handicap)
     - 1. D4
       + Variation B: Q14
       - Variation C: Q16
         - 2. Q16
     - 2. D17
     ...

    each node has a number, and an icon (black/white stone, usually)

    feature: it has a right-click menu, for handy access to things like
    'delete this variation', or 'insert variation here'.
    """

    def __init__(self, game):
        """
        DOCUMENT ME!
        """
        gtk.TreeView.__init__(self)

        self.game = game

        self.set_headers_visible(False)
        self.set_rules_hint(True)
        self.set_enable_search(True) # ??

        self.model = gtk.TreeStore(str, gtk.gdk.Pixbuf)
        self.set_model(self.model)

        column = gtk.TreeViewColumn()
        column.set_title("Moves") # (but it won't be shown)

        cell_renderer = gtk.CellRendererPixbuf()
        column.pack_start(cell_renderer, False)
        column.set_attributes(cell_renderer, pixbuf=1)
        column.set_spacing(5)

        cell_renderer = gtk.CellRendererText()
        column.pack_start(cell_renderer, True)
        column.set_attributes(cell_renderer, text=0)

        self.append_column(column)

        #
        # now we'll fill the tree with nodes.
        #

        self.fill_branch(None, self.game.head)

        # add listener -- this is really "cursor changed", but there doesn't
        # seem to be any way to get selection-changed, and this is simply a
        # more general event.
        self.connect("cursor-changed", self.on_selection_changed)

        # key listener -- make it so <- and -> arrows expand/collapse.
        self.connect("key-press-event", self.on_key_pressed)

    def on_selection_changed(self, widget):
        """
        DOCUMENT ME!
        """
        __pychecker__ = 'unusednames=widget'
        (model, paths) = self.get_selection().get_selected_rows()
        # DON'T DO THIS: can i store a ptr to the (sgf) node, in the (gtk) node?  (very memory inefficient!)
        # ALTERNATIVE 1: i have (221, 0, 1) -- this means "take head, go to c[0] 221 times, take c[0+1],
        # then take c[0] 1 time".  so just follow those on the sgf tree.  con: it's o(n).
        # (but we're O(n) already, aren't we?)
        # A-HA!  we can combine the O(n) things:
        # - start at head
        # - follow the instructions (221,0,1), playing each stone as you go -- which we have to do, anyway!
        # only gotcha: if it has an even number of elements, pretend to add a 0 -- (221,0) -> (221,0,0)

        path = list(paths[0])
        if len(path) % 2 != 1: # e.g., (221,0) -> (221,0,0) -- the "variation x" node, but use the first child.
            path += [0]

        ptr = self.game.head

        while True:
            # take c[0] /n/ times
            for i in range(path[0]):
                ptr = ptr.children[0]
            path = path[1:]

            # if there's more, take the proper child, and repeat
            if path:
                ptr = ptr.children[path[0] + 1]
                path = path[1:]
            else:
                break

        # move cursor
        self.game.cursor.move_to(ptr)
        self.game.emit("cursor_moved", self.game.cursor)

    def fill_branch(self, gtk_parent_node, sgf_node):
        """
        DOCUMENT ME!
        """
        while True:
            # add this node
            text = sgf_node.get_text()
            icon = sgf_node.get_icon()
            my_gtk_node = self.model.append(gtk_parent_node, [text, icon])

            # leaf?  stop
            if len(sgf_node.children) == 0:
                return

            # variations?
            if len(sgf_node.children) > 1:
                ## for i,child in enumerate(sgf_node.children[1:]):
                for i in range(len(sgf_node.children) - 1): # FIXME: enumerate()!
                    letter = chr(ord('A') + i + 1)
                    if 'B' in sgf_node.children[i+1].properties:
                        move = sgf_node.children[i+1].properties["B"]
                    elif 'W' in sgf_node.children[i+1].properties:
                        move = sgf_node.children[i+1].properties["W"]
                    else:
                        move = u'\N{EM DASH}'
                    variation_b = self.model.append(my_gtk_node,
                                                    ["Variation %s - %s" % (letter, move), None])
                    self.fill_branch(variation_b, sgf_node.children[i+1])

            # go to next A-branch
            sgf_node = sgf_node.children[0]

    def on_key_pressed(self, treeview, event):
        """A key was pressed; if it was left- or right-arrow,
        collapse or expand the current node.  (This is usually
        shift-arrow, but it's so handy I want the non-shifted
        keys to work, too.)
        """
        left = gtk.gdk.keyval_from_name('Left')
        right = gtk.gdk.keyval_from_name('Right')

        if event.keyval in (left, right):
            (model, rows) = treeview.get_selection().get_selected_rows()

            if event.keyval == left:
                # if at an expanded node, collapse
                if treeview.row_expanded(rows[0]):
                    treeview.collapse_row(rows[0])
                # TODO: select my parent (whose path is rows[0][:-1])
            else:
                # if at a collapsed node, expand it
                if not treeview.row_expanded(rows[0]):
                    treeview.expand_row(rows[0], open_all=False)
                # TODO: if at an expanded node, go to first variation?
            return True # =stop propagating

        return False # =keep propagating

# BACKWARDS COMPATIBILITY:
GameView = GameTreeView

# ----------------------------------------
def test():
    w = gtk.Window()

    from sgf import load
#    my_sgf = load("kogos.sgf")
    my_sgf = load("Symbols.sgf")

    g = GameTreeView(my_sgf)
    s = gtk.ScrolledWindow()
    s.add(g)
    w.add(s)

    w.show_all()
    gtk.main()

if __name__ == '__main__':
    test()
